package graph

import (
    "fmt"
)

func CreateEdgeMap(size int) *EdgeMap {
    g := new(EdgeMap)
    g.edges = make(map[VertexID]map[VertexID]bool)
    g.capacity = size
    return g
}

// EdgeMap functions

// Add single node to graph
func (g *EdgeMap) AddVertex(v VertexID) bool {
    if _, ok := g.edges[v]; ok {
        // Should panic here
        return false
    }
    g.edges[v] = make(map[VertexID]bool)
    return true
}

// Touch single node to graph
func (g *EdgeMap) touchVertex(v VertexID) {
    if _, ok := g.edges[v]; !ok {
        g.edges[v] = make(map[VertexID]bool)
    }
}

func (g *EdgeMap) RemoveVertex(v VertexID) {
    if _, ok := g.edges[v]; !ok {
        fmt.Println("Warning: trying to remove a node that doesn't exist")
    }
    delete(g.edges, v)
    for _, connectedVertices := range g.edges {
        // Remove incoming edges to node
        delete(connectedVertices, v)
    }
}

func (g *EdgeMap) fillVertices() {
    var i VertexID = 0
    for ; len(g.edges) < g.capacity; i++ {
        g.AddVertex(i)
    }
}

func (g *EdgeMap) AddEdge(src, dst VertexID) bool {
    g.touchVertex(src)
    g.touchVertex(dst)

    if exists, ok := g.edges[src][dst]; ok && exists {
        //fmt.Println("Edge already exists")
        return false
    }

    g.edges[src][dst] = true
    g.edges[dst][src] = true
    g.edgeCount++
    return true
}

func (g *EdgeMap) checkVertex(v VertexID) bool {
    _, ok := g.edges[v]
    return ok
}

func (g *EdgeMap) RemoveEdge(src, dst VertexID) {
    if g.checkVertex(src) && g.checkVertex(dst) {
        // Both vertices exist
        delete(g.edges[src], dst)
        delete(g.edges[dst], src)
        g.edgeCount--
    } else {
        fmt.Println("Tried to remove edge between one or more non-existent vertices!")
    }
}

func (g *EdgeMap) CheckEdge(src, dst VertexID) bool {
    if g.checkVertex(src) {
        return g.edges[src][dst]
    }
    return false
}

func (g *EdgeMap) Order() int {
    return len(g.edges)
}

func (g *EdgeMap) EdgeCount() int {
    return g.edgeCount
}

func (g *EdgeMap) VertexIterator() <-chan VertexID {
    ch := make(chan VertexID)
    go func() {
        for vertex, _ := range g.edges {
            ch <- vertex
        }
        close(ch)
    }()
    return ch
}

func (g *EdgeMap) NeighborsIterator(src VertexID) <-chan VertexID {
    ch := make(chan VertexID)
    go func() {
        if connectedMap, ok := g.edges[src]; ok {
            for vertex, edge := range connectedMap {
                //fmt.Println(vertex, edge)
                if edge { ch <- vertex }
            }
        }
        close(ch)
    }()
    return ch
}
